"""Used to count the number of login trials. If no many then apply penalty.
"""

import datetime

from cibynet.model import meta
from cibynet.model.tables import login_temporizing

# (# X attempts, PENALTY in Y seconds)
# if the number of attempts is larger, then wait Y seconds 
# before considering login requests from one IP.
ATTEMPTS_PENALTIES = [  (  0,  0),
                        (  5,  2),
                        ( 10,  5),
                        ( 15, 10),
                        ( 20, 60),
                      ]

def isTemporized(ip, now=None):
  """Returns True if the IP is being prevented from trying to authenticate.
  False otherwise.
  Delete old temporizers from DB.
  
  Arguments:
    - ip: string, the ip you are looking at.
    - now: optional datetime.datetime, what time is it?
  """
  now = now or datetime.datetime.now()
  session = meta.Session
  session.execute(login_temporizing.delete(login_temporizing.c.date < now))
  session.commit()
  obj_q = session.query(LoginTemporizer).filter(LoginTemporizer.ip == ip)
  obj_q = obj_q.order_by(login_temporizing.c.id.asc())
  temporizer = obj_q.first()
  return bool(temporizer)
  

def add(ip, login):
  """Returns how many seconds the server should wait before accepting 
  new authentication requests.
  """
  now = datetime.datetime.now()
  yesterday = now - datetime.timedelta(days=1)
  session = meta.Session
  fal = FailedLoginAttempt(ip, login, now=now)
  session.add(fal)
  session.commit()
  obj_q = session.query(FailedLoginAttempt)
  obj_q = obj_q.filter(FailedLoginAttempt.ip == ip)
  obj_q = obj_q.filter(FailedLoginAttempt.date <= now)
  obj_q = obj_q.filter(FailedLoginAttempt.date > yesterday)
  nb = obj_q.count()
  for t in ATTEMPTS_PENALTIES:
    if nb > t[0]: 
      penalty = t[1]
  if penalty:
    end_penalty = now + datetime.timedelta(seconds=penalty)
    session.add(LoginTemporizer(ip, end_penalty))
    session.commit()
  return penalty
  

class FailedLoginAttempt(object):
  """Represents one failed login attempt on the Web site.
  """
  
  def __init__(self, ip, login, now=None):
    """
    
    Arguments:
      - ip: string, the ip trying to log in.
      - login: string, the login requested.
      - now: optional, datetime.datetime object. Default value: now().
    """
    now = now or datetime.datetime.now()
    self.login = login
    self.ip = ip
    self.date = now
    
    
class LoginTemporizer(object):
  """Associate an IP with a date before which we should not consider any
  authentication request.
  """
  
  def __init__(self, ip, date):
    """Create a login temporizer.
    
    Arguments:
      - ip: string, the ip to look after.
      - date: datetime.datetime, the date before which we should not consider 
              authentification requests from user.
    """
    self.ip = ip
    self.date = date
    